﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FaultBackService.Shared;
using FaultBackService.DataHelper;
using System.Threading;

namespace FaultBackService
{
    /// <summary>
    /// 异步回调委托
    /// </summary>
    public delegate void CallbackDelegate();

    /// <summary>
    /// 异步进程处理方法类
    /// </summary>
    class ThreadProc
    {
        private object thisLock = new object();
        /// <summary>
        /// 异步对时
        /// </summary>
        /// <param name="dlg"></param>
        public void CheckTimeForScada(object dlg)
        {

            //数据库当前时间
            try
            {
                var currentServerTime = new RealTimeFaultTransaction().GetCurrentTimeOfDB();
                lock (thisLock)
                {
                    if (Global.SCADAConnectionState == false) Global.SCADAConnectionState = true;
                }

                //对时完成
#if DEBUG
                if (currentServerTime.Minute % 1 == 0)   //分钟逢十,则对时完成
#endif

                {
                    //写入日志
                    Log log = new Log();
                    log.ChecktimeCompleted(currentServerTime.ToString());
                    log.StartCycleRead();

                    //异步回调，回调实时故障事务执行
                    ((CallbackDelegate)dlg)();
                }
            }
            catch (System.Data.SqlClient.SqlException e)
            {
                lock (thisLock)
                {
                    if (Global.SCADAConnectionState == true)
                    {
                        Global.SCADAConnectionState = false;
                    }
                    new Log().ReadSCADAFail(e.Message);
                }
            }
        }

        /// <summary>
        /// 获取SCADA十分钟数据最新时间，修改数据库连接状态
        /// </summary>
        /// <param name="dlg"></param>
        public void GetLastTenMeanTimeOfScada(object dlg)
        {

            try
            {
                var time = new BLL.t_TurbDataGeneric().GetLastTimeStamp();

#if DEBUG
                //time = new DateTime(2016, 12, 15, 0, 35, 0);
#endif

                lock (thisLock)
                {
                    //赋值 Global.CurrentTenMeanTimeOfScada
                    Global.CurrentTenMeanTimeOfScada = time;
                    if (Global.SCADAConnectionState == false) Global.SCADAConnectionState = true;
                }
                if (Global.CurrentTenMeanTimeOfScada == Global.DefaultTime)
                {
                    new Log().DataIsEmpty();
                }
                else
                {
                    new Log().GetScadaLastTenMeanTimeSuccess(Global.CurrentTenMeanTimeOfScada);
                    //异步回调，回调实时故障事务执行
                    //((CallbackDelegate)dlg)();
                }

            }
            catch (System.Data.SqlClient.SqlException e)
            {
                lock (thisLock)
                {
                    if (Global.SCADAConnectionState) Global.SCADAConnectionState = false;
                }

                new Log().ReadSCADAFail(e.Message);
            }
        }


        /// <summary>
        /// 趋势数据每日分析进程方法
        /// </summary>
        /// <returns></returns>
        public void DoTrendTransactionOnDaily(object obj)
        {
            /*
             1. 判断时间.每天3-5点执行，判断当天的事务是否已执行
             2. 获取所有的TrendModel
             3. 获取每台风机在每个TrendModel稳定执行后的时间戳
             4. 获取与时间戳对应的每个传感器的值，并写入数据库
             */

            try
            {
                DateTime yesterday;


#if DEBUG
                yesterday = new DateTime(2017, 3, 2);
                if (Global.LastTrendDailyDate >= yesterday) return;
#else
                yesterday = DateTime.Today.AddDays(-1);
                if (DateTime.Now.Hour < 11 || DateTime.Now.Hour > 12 || Global.LastTrendDailyDate >= yesterday) return;  //考虑8小时延迟,[11:00-12:59]
#endif

                /* 判断时间(3点-5点)，判断当天的事务是否已执行 */


                /* 获取所有的可用的TrendModel */
                var trendModelList = new BLL.TrendModel().GetAllEnabled();

                /* 获取每个风机/TrendModel对的稳定功率的时间戳 */
                var tenMeanDataList = new BLL.t_TurbDataGeneric().GetViewList2(yesterday);   //获取前一天的SCADA十分钟数据集合
                var stableTimeList = new List<Models.TrendStableTime>();   //缓存适用的实时功率的时间戳
                var stableCount = new Dictionary<TrendModelTurbine, int>();   //稳定运行计数器

                foreach (var tenMeanData in tenMeanDataList)
                {
                    foreach (var trendModel in trendModelList)
                    {
                        var trendModelTurbine = new TrendModelTurbine(trendModel.ModelId, tenMeanData.NodeID);
                        var goalCount = trendModel.TimeRange / 10;   //十分钟一次数据

                        if (!stableCount.ContainsKey(trendModelTurbine))
                        {
                            stableCount.Add(trendModelTurbine, 0);
                        }
                        else if (stableCount[trendModelTurbine] < goalCount)
                        {
                            if (tenMeanData.kW_Mean >= (trendModel.PowerPoint - trendModel.Accuracy)
                                && tenMeanData.kW_Mean <= (trendModel.PowerPoint + trendModel.Accuracy))
                            {
                                stableCount[trendModelTurbine]++;
                                if (stableCount[trendModelTurbine] == goalCount)
                                {
                                    stableTimeList.Add(new Models.TrendStableTime
                                    {
                                        TurbineId = tenMeanData.NodeID,
                                        TrendModelId = trendModel.ModelId,
                                        PowerPoint = trendModel.PowerPoint,
                                        Accuracy = trendModel.Accuracy,
                                        TimeRange = trendModel.TimeRange,
                                        RealPower = tenMeanData.kW_Mean,
                                        TimeStamp = tenMeanData.TStampOfMidPoint
                                    });
                                }
                            }
                            else
                            {
                                stableCount[trendModelTurbine] = 0;   //清零
                            }
                        }
                    }
                }

                /* 获取与时间戳对应的每个传感器的值，并写入数据库 */
                var gboxCount=new BLL.Trend_GBox(stableTimeList, tenMeanDataList).GetStableValueListAndWriteToDB();   //齿轮箱温度
                var genCount=new BLL.Trend_Gen(stableTimeList, tenMeanDataList).GetStableValueListAndWriteToDB();   //发电机温度

                Global.LastTrendDailyDate = yesterday;
                new Log().TrendSuccess();   //完成并写入日志
                new Log().Trend_WriteCount(@"齿轮箱温度", gboxCount);
                new Log().Trend_WriteCount(@"发电机温度", genCount);
            }
            catch (Exception e)
            {
                new Log().TrendError(e.Message);   //写错误日志
            }
        }

        /// <summary>
        /// 执行实时故障的实时分析事务
        /// </summary>
        /// <param name="obj"></param>
        public void DoRealTimeFaultTransactionOnRealTime(object obj)
        {
            /*****
            功能：
            1. 判断是否重新开启Timer
            2. 读取SCADA数据库t_TurbDataGeneric表
            3. 写入TenMeanFarmData,TenMeanData
            4. 写入RealTimeFaultData
            5. 修改数据库连接状态
            *****/

            try
            {
                /* 开启下一个Timer */
                lock (thisLock)
                {
                    Global.RealTimeCount++;
                    if (Global.RealTimeCount >= 144)
                    {
                        Global.RealTimeCount = 0;
                        ServiceHelper.StartNewTimerForRealTimeFault();
                        return;
                    }
                }

                /* 读取SCADA数据库 */
                //指定十分钟数据时间
                DateTime dataTime;
                lock (thisLock)
                {
                    dataTime = Global.CurrentTenMeanTimeOfScada;
                    //下个十分钟
                    Global.CurrentTenMeanTimeOfScada = Global.CurrentTenMeanTimeOfScada.AddMinutes(10);
                }

                RealTimeFaultTransaction transaction = new RealTimeFaultTransaction();

                //读取SCADA十分钟数据t_TurbDataGeneric
                var dataIsNew = transaction.ReadNormalTenMeanOfLastCycle(dataTime);

                //解析SCADA十分钟数据,向故障数据库中写入数据
                if (dataIsNew)
                {
                    transaction.ParseTenMeanData(dataTime);
                }

                new Log().RealTimeFaultSuccess();
            }
            catch (Exception e)
            {
                new Log().RealTimeFaultError(e.Message);
            }
        }


        // <summary>
        // 执行实时故障分析事务，编辑数据库连接状态
        // </summary>
        // <param name="obj"></param>
        //public void DoRealTimeFaultTransaction(object obj)
        //{
        //    //以10分钟为周期，异步读取SCADA数据库，写入十分钟数据，写入实时故障数据,修改数据库连接状态
        //    RealTimeFaultTransaction transaction = new RealTimeFaultTransaction();

        //    try
        //    {
        //        //读取SCADA十分钟数据
        //        var dataIsNew = transaction.ReadNormalTenMeanOfLastCycle();
        //        lock (thisLock)
        //        {
        //            if (Global.SCADAConnectionState == false) Global.SCADAConnectionState = true;   //修改数据库连接状态
        //        }

        //        //解析SCADA十分钟数据,向故障数据库中写入数据
        //        if (dataIsNew)
        //        {
        //            try
        //            {
        //                transaction.ParseTenMeanData();
        //                lock (thisLock)
        //                {
        //                    if (Global.FaultConnectionState == false) Global.FaultConnectionState = true;   //修改数据库连接状态
        //                }
        //            }
        //            catch (System.Data.SqlClient.SqlException e)
        //            {
        //                lock (thisLock)
        //                {
        //                    if (Global.FaultConnectionState == true)
        //                    {
        //                        Global.FaultConnectionState = false;  //连接故障数据库失败，修改状态
        //                    }
        //                    //写日志
        //                    new Log().ConnectFaultDatabaseFail(e.Message);
        //                }
        //            }
        //        }

        //    }
        //    catch (System.Data.SqlClient.SqlException e)
        //    {
        //        lock (thisLock)
        //        {
        //            //读取SCADA失败，修改状态
        //            if (Global.SCADAConnectionState) Global.SCADAConnectionState = false;

        //            //写日志
        //            new Log().ReadSCADAFail(e.Message);
        //        }
        //    }
        //}

        /// <summary>
        /// 计时器异步方法，循环执行：执行实时故障的每日分析事务，分析昨天的数据
        /// </summary>
        /// <param name="obj"></param>
        public void DoRealTimeFaultTransactionOnDaily(object obj)
        {
            //执行实时故障每日分析事务
            var yesterday = DateTime.Now.AddDays(-1);

            if (DateTime.Now.Hour >= 9 && DateTime.Now.Hour <= 10    //每天晚上1~2点间执行一次，考虑8小时延迟 [9:00-10:59]
                && yesterday > Global.LastRealTimeFaultDailyDate)   //且昨天的数据尚未分析
            {
                try
                {
                    new Log().RealTimeFaultDailyStart();
                    DoRealTimeFaultDailyTransaction(yesterday);   //执行事务
                    Global.LastRealTimeFaultDailyDate = yesterday;  //修改最新日期
                }
                catch (System.Data.SqlClient.SqlException e)
                {
                    new Log().RealTimeFaultDailyError(e.Message);
                }

            }
        }

        /// <summary>
        /// 执行当日实时故障处理事务
        /// </summary>
        /// <param name="obj"></param>
        public void DoRealTimeFaultDailyTransaction(DateTime dayOfData)
        {
            RealTimeFaultDailyTransaction transaction = new RealTimeFaultDailyTransaction(dayOfData);
            transaction.Prase();
        }
    }

    struct TrendModelTurbine
    {
        public int TrendModelId;
        public int TurbineId;
        public TrendModelTurbine(int trendModelId, int turbineId)
        {
            TrendModelId = trendModelId;
            TurbineId = turbineId;
        }
    }
}
